home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Mac Power 1997 December
/
MACPOWER-1997-12.ISO.7z
/
MACPOWER-1997-12.ISO
/
AMUG
/
PROGRAMMING
/
Raven 1.2.sit
/
Raven 1.2
/
Source
/
Foundation
/
OS
/
ZPatch.cpp
< prev
next >
Wrap
Text File
|
1997-06-18
|
7KB
|
251 lines
/*
* File: ZPatch.cpp
* Summary: Classes to help with patching traps.
* Written by: Jesse Jones
*
* Copyright ゥ 1996 Jesse Jones.
* For conditions of distribution and use, see copyright notice in ZTypes.h
*
* Change History (most recent first):
*
* <-> 1/13/96 JDJ Created (based on MacApp's class).
*/
#include <ZPatch.h>
#include <OSUtils.h>
#include <Traps.h>
#include <ZDebug.h>
#include <ZExceptions.h>
// ===================================================================================
// Internal Functions
// ===================================================================================
//---------------------------------------------------------------
//
// GetTrapType
//
//---------------------------------------------------------------
static SignedByte GetTrapType(ushort theTrap)
{
return (theTrap & 0x0800) ? ToolTrap : OSTrap;
}
#pragma mark -
// ===================================================================================
// class TTrapPatch
// ===================================================================================
TrapPatchPtr TTrapPatch::msPatchList = nil;
//---------------------------------------------------------------
//
// TTrapPatch::TTrapPatch
//
//---------------------------------------------------------------
TTrapPatch::TTrapPatch()
{
mTrapNum = 0;
mOldTrapAddr = nil;
mPatchRoutine = nil;
mNextPatch = nil;
}
//---------------------------------------------------------------
//
// TTrapPatch::PatchTrap
//
//---------------------------------------------------------------
void TTrapPatch::PatchTrap(ushort theTrapNum, void* theRoutine)
{
ASSERT(mPatchRoutine != nil); // Should have been set by the subclass.
mTrapNum = theTrapNum;
mNextPatch = msPatchList;
msPatchList = this;
mOldTrapAddr = NGetTrapAddress(theTrapNum, GetTrapType(theTrapNum));
NSetTrapAddress((UniversalProcPtr) theRoutine, theTrapNum, GetTrapType(theTrapNum));
}
//---------------------------------------------------------------
//
// TTrapPatch::GetPreviousPatchPtr
//
// GetPreviousPatchPtr: walks the patch list backwards to return
// the patch record just prior to (*thePatchPtr) in the patch list.
//
//---------------------------------------------------------------
TrapPatchPtr TTrapPatch::GetPreviousPatchPtr() const
{
TrapPatchPtr tempPatchPtr = msPatchList;
if (tempPatchPtr == this)
return nil;
while (tempPatchPtr != nil && tempPatchPtr->mNextPatch != this)
tempPatchPtr = tempPatchPtr->mNextPatch;
return tempPatchPtr;
}
//---------------------------------------------------------------
//
// TTrapPatch::GetNewerPatchPtr
//
// GetNewerPatchPtr: returns a newer patch record in the patch list
// which has the *same* trapNum as thePatch.
//
//---------------------------------------------------------------
TrapPatchPtr TTrapPatch::GetNewerPatchPtr() const
{
TrapPatchPtr newerPatch = nil;
TrapPatchPtr tempPatchPtr = msPatchList;
while (tempPatchPtr != nil && tempPatchPtr != this) {
if (tempPatchPtr->mTrapNum == mTrapNum)
newerPatch = tempPatchPtr;
tempPatchPtr = tempPatchPtr->mNextPatch;
}
return newerPatch;
}
//---------------------------------------------------------------
//
// TTrapPatch::UnpatchTrap
//
//---------------------------------------------------------------
void TTrapPatch::UnpatchTrap()
{
// You can't patch nothing, so we use the old trap address to keep track of if we
// have a patch installed.
if (mOldTrapAddr == nil)
return;
// If this trap has a newer patch than the patch we're removing, then we have to take
// some extra special precautions. We have to muck with that patch's mOldTrapAddr to
// point to this patch record's mOldTrapAddr. We can pretty well ignore the case of
// an older patch on this same trap since the trapaddress in our patch record will
// be correct.
// only set the trap address if there *isn't* a newer patch
TrapPatchPtr newerPatchPtr = this->GetNewerPatchPtr();
if (newerPatchPtr == nil)
NSetTrapAddress(mOldTrapAddr, mTrapNum, GetTrapType(mTrapNum));
else
// set up newerPatchPtr patch record so that it points to thePatch's mOldTrapAddr
newerPatchPtr->mOldTrapAddr = mOldTrapAddr;
mOldTrapAddr = nil;
if (mPatchRoutine) {
DisposeRoutineDescriptor(mPatchRoutine);
mPatchRoutine = nil;
}
// Unlink the patch from the linked list of patches
if (this == msPatchList)
msPatchList = mNextPatch;
else {
TrapPatchPtr aPatchPtr = this->GetPreviousPatchPtr();
if (aPatchPtr != nil) // Couldn't find thePatch, don't unpatch it
aPatchPtr->mNextPatch = mNextPatch;
}
mNextPatch = nil;
}
//---------------------------------------------------------------
//
// TTrapPatch::UnpatchAll
//
//---------------------------------------------------------------
void TTrapPatch::UnpatchAll()
{
while (msPatchList != nil)
{
msPatchList->UnpatchTrap();
}
}
#pragma mark -
// ===================================================================================
// class TPatchExitToShell
// ===================================================================================
enum {
uppExitToShellProcInfo = kPascalStackBased
};
#if GENERATINGCFM
typedef UniversalProcPtr ExitToShellUPP;
#define CallExitToShellProc(userRoutine) ¥
CallUniversalProc((UniversalProcPtr)(userRoutine), uppExitToShellProcInfo)
#define NewExitToShellProc(userRoutine) ¥
(ExitToShellUPP) NewRoutineDescriptor((ProcPtr)(userRoutine), uppExitToShellProcInfo, GetCurrentISA())
#else
typedef ProcPtr ExitToShellUPP;
#define CallExitToShellProc(userRoutine) ¥
(*(userRoutine))()
#define NewExitToShellProc(userRoutine) ¥
(ExitToShellUPP)(userRoutine)
#endif
//---------------------------------------------------------------
//
// TPatchExitToShell::Install
//
//---------------------------------------------------------------
void TPatchExitToShell::Install(ExitToShellType routine)
{
ASSERT(mPatchRoutine == nil);
mPatchRoutine = NewExitToShellProc(StripAddress(routine));
ThrowIfMemFail(mPatchRoutine);
this->PatchTrap(_ExitToShell, mPatchRoutine);
}
//---------------------------------------------------------------
//
// TPatchExitToShell::Remove
//
//---------------------------------------------------------------
void TPatchExitToShell::Remove()
{
mRemovedTrapAddr = mOldTrapAddr;
this->UnpatchTrap();
ASSERT(mPatchRoutine == nil);
}
//---------------------------------------------------------------
//
// TPatchExitToShell::CallRemoved
//
//---------------------------------------------------------------
void TPatchExitToShell::CallRemoved()
{
if (mRemovedTrapAddr == nil)
mRemovedTrapAddr = mOldTrapAddr;
CallExitToShellProc(mRemovedTrapAddr);
}